This is an R-code companion to Session 7, and the contents here encompass just about all the material in that session. During the lecture associated with the lesson, we showed some OpenGL-based animations of the MCMC sampler for the inbreeding model, but the code for that is implemented in C, and is not super accessible. So, the goal here is to implement, in R, the model and MCMC for the model using the several different types of samplers discussed in the session.

Let’s load Hadley’s tidyverse and other packages we need before we get going. The following will also install them if you don’t have them.

packs <- c("tidyverse", "plotly", "viridis", "broom")

# install any that are not here
install_em <- setdiff(packs, rownames(installed.packages()))
if (length(install_em) > 0) install.packages(pkgs = install_em)

# load em up
dump <- lapply(packs, function(x) library(x, character.only = TRUE))
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ─────────────────────────────────────────────────────────── tidyverse 1.3.1 ──
✔ ggplot2 3.3.6     ✔ purrr   0.3.4
✔ tibble  3.1.7     ✔ dplyr   1.0.9
✔ tidyr   1.2.0     ✔ stringr 1.4.0
✔ readr   2.1.2     ✔ forcats 0.5.1
── Conflicts ────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
Registered S3 methods overwritten by 'htmltools':
  method               from         
  print.html           tools:rstudio
  print.shiny.tag      tools:rstudio
  print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout

Loading required package: viridisLite

The joint probability

As discussed in the previous session, this is just the product of the priors and the likelihoods. In its full glory, it looks like. (For a review of how that joint density was developed, see the discussion at the very end \[ \begin{aligned} P(n_{AA}, n_{Aa}, n_{aa}, f, p | \alpha_f, \beta_f, \alpha_p, \beta_p) & = \frac{\Gamma(\alpha_f + \beta_f)}{\Gamma(\alpha_f)\Gamma(\beta_f)}f^{\alpha_f - 1}(1-f)^{\beta_f - 1} \frac{\Gamma(\alpha_p + \beta_p)}{\Gamma(\alpha_p)\Gamma(\beta_p)}p^{\alpha_p - 1}(1-p)^{\beta_p - 1} \times \\ & \frac{n!}{n_{AA}! + n_{Aa}! + n_{aa}!}~ [fp + (1-f)p^2]^{n_{AA}}~ [(1-f)2p(1-p)]^{n_{Aa}}~ [f(1-p) + (1-f)(1-p)^2]^{n_{aa}} \end{aligned} \] We will be using this in MCMC in which the the hyperpriors \((\alpha_f, \beta_f, \alpha_p, \beta_p)\) and the data are fixed. Thus the terms (factors) that involve only the data and the hyperpriors are constants that will drop out of the Hastings ratio, so they can be safely ignored. So, our joint probability can be computed as something that looks like: \[ \begin{aligned} P(n_{AA}, n_{Aa}, n_{aa}, f, p | \alpha_f, \beta_f, \alpha_p, \beta_p) & \propto f^{\alpha_f - 1}(1-f)^{\beta_f - 1} p^{\alpha_p - 1}(1-p)^{\beta_p - 1} \times \\ & ~~~~[fp + (1-f)p^2]^{n_{AA}}~ [(1-f)2p(1-p)]^{n_{Aa}}~ [f(1-p) + (1-f)(1-p)^2]^{n_{aa}} \end{aligned} \] We will implement this in a function that returns the log of the above quantity so that we won’t run into underflow issues with very large samples:

#' the log of the joint probability of all the data and paramaters given the priors
#'
#' This is computed having dropped all the constant factors in the probability.
#' @param n a vector of three elements: (nAA, nAa, naa), the number of AA's, the
#' number of Aa's, and the number of aa's
#' @param f the inbreeding coeffient
#' @param p the frequency of the A allele
#' @param pri a vector of four components: (alpha_f, beta_f, alpha_p, beta_p) which are the 
#' beta parameters for the priors on f and p.  By default they are all 1.
log_joint_prob <- function(n, f, p, pri = c(1, 1, 1, 1)) {
  # not going to do much error checking here
  
  # compute the raw values, anything outside of the unit interval we will send
  # back as NaN
  ifelse(f <= 0 | f >= 1 | p <= 0 | p >= 1, NaN,
         log(f) * (pri[1] - 1) + 
           log(1 - f) * (pri[2] - 1) +
           log(p) * (pri[3] - 1) +
           log(1 - p) * (pri[4] - 1) +
           log(f * p + (1 - f) * p ^ 2) * n[1] +
           log((1 - f) * 2 * p * (1 - p)) * n[2] + 
           log(f * (1 - p) + (1 - f) * (1 - p) ^ 2) * n[3])
  
  

}

Note that this function is vectorized over \(f\) and \(p\), but not \(n\) or the priors.

A 3-D plot

We can compute the joint probability of all the variables easily, and, because this is a toy problem in two dimensions, we can visualize roughly what the posterior surface will look like by computing values on a grid and normalizing those values so they sum to one. Let’s do that, since it is a good chance to introduce the plotly package to anyone that might not yet know it.

So, let’s take the example from the lecture and set our data to be \(n_{AA} = 30\), \(n_{Aa} = 10\), and \(n_{aa} = 10\). Those are the expected values if \(f = 0.5\) and \(p = 0.7\),

ndata <- c(30, 10, 10)

and then compute the log prob, exponentiate it, and normalize it over a grid of value for \(f\) and \(p\):

f_vals <- seq(0, 1, by = 0.03)
p_vals <- seq(0, 1, by = 0.03)

# make a tidy tibble of values 
grid_vals <- expand.grid(f = f_vals, p = p_vals) %>%
  as_tibble() %>%
  mutate(joint = exp(log_joint_prob(ndata, f, p))) %>%
  mutate(norm_joint = joint / sum(joint, na.rm = TRUE)) %>%
  select(-joint)

# then put those values into a matrix, with rows corresponding to f and cols to p
probs <- matrix(grid_vals$norm_joint, nrow = length(f_vals), ncol = length(p_vals))

Now we can plot it with plotly:

plot_ly(x = ~p_vals, y = ~f_vals, z = ~probs) %>%
  add_surface()

Try interacting with that plot, especially if you are not familiar with plotly. You can zoom, pan, and revolve it, and you can also look at individual values by mousing over within the plot.

“2-D” Metropolis-Hastings Sampler

We now start our forays into different MCMC samplers, roughly following the lecture notes from the session. The first is a sampler in which we propose changes to both \(f\) and \(p\) and then we accept or reject both of those proposaled changes, together, in one fell swoop, according to the Hastings Ratio.

For our proposals in this case we will use two independent, symmmetrical normal distributions centered on the current values. We will wrap up the whole process in a single function called mcmc_2d_mh().

#' function to do MCMC using a "2-D" Metropolis-Hastings sampler
#' @param ndata a three-vector (nAA, nAa, naa) of the observed data
#' @param pri a vector of four components: (alpha_f, beta_f, alpha_p, beta_p)
#' @param init a two vector of starting values (f, p).  Each should be within the
#' unit interval.
#' @param sweeps the number of sweeps (i.e proposed changes) to do in the MCMC chain.
#' @param f_sd the standard deviation of the normal distribution for proposing new values to f
#' @param p_sd the standard deviation of the normal distribution for proposing new values to p
#' @return returns a tibble of proposals made, values visited, values of MH ratio, etc
mcmc_2d_mh <- function(ndata, 
                       pri = c(1, 1, 1, 1), 
                       init = c(.2, .5), 
                       sweeps = 500,
                       f_sd = 0.07,
                       p_sd = 0.07) {

  # create vectors in which to store output. Note that we will be storing 
  # the proposed values and the MH-ratio each sweep, too, for later analysis.
  f <- p <- fprop <- pprop <- mh_ratio <- rep(NA_real_, sweeps + 1)
  accepted_f <- accepted_p <- rep(NA, sweeps + 1)
  
  # put initial values in
  f[1] <- init[1]
  p[1] <- init[2]
  
  # then cycle over sweeps
  for (i in 1:sweeps) {
    
    # propose new values
    fprop[i] <- rnorm(1, f[i], f_sd)
    pprop[i] <- rnorm(1, p[i], p_sd)
    
    # compute the hastings ratio
    # the log M-H ratio is the difference of the log joint probs.
    # since the proposal distributions are symmetrical they drop out of the ratio.
    mh_ratio[i] <- exp(log_joint_prob(ndata, fprop[i], pprop[i], pri) -
      log_joint_prob(ndata, f[i], p[i], pri))
    
    # now, if mh_ratio[i] is NaN it means that f or p was proposed outside of the unit interval
    # and it should be rejected immediately.  If not, then we simulate a uniform R.V. on (0, 1)
    # and reject the proposal if that number is greater than the MH-ratio.
    if (is.nan(mh_ratio[i]) || runif(1) > mh_ratio[i]) {# reject!
      accepted_f[i] <- FALSE
      accepted_p[i] <- FALSE
      f[i + 1] <- f[i]
      p[i + 1] <- p[i]
    } else {# accept!
      accepted_f[i] <- TRUE
      accepted_p[i] <- TRUE
      f[i + 1] <- fprop[i]
      p[i + 1] <- pprop[i]
    }
    
  }
  
  # in the end, make a tibble and return
  tibble(sweep = 1:(sweeps + 1),
         f = f,
         p = p, 
         proposed_f = fprop,
         proposed_p = pprop,
         mh_ratio = mh_ratio,
         accepted_f = accepted_f,
         accepted_p = accepted_p
         )
}

A brief note: In the above function (and the one following) we are being careful to record not just the current state of the chain, but also every proposed value. Typically this is not done in MCMC. Rather, it is more usual to simply record the state of the chain at each sweep (or at some “thinned” interval of sweeps). However we wanted to keep a full record of the progression of all the variables so that they would be available for students to peruse or analyze.

Component-wise Metropolis-Hastings Sampler

Rather than proposing changes to both \(f\) and \(p\) before accepting or rejecting them, we can propose just a change to \(f\) (say) and accept or reject the proposal, and then propose just a change to \(p\), and then accept or reject that. This is called component-wise Metropolis-Hastings sampling. Underlying it is a central theme in MCMC, which is that just one or a few dimensions can be changed with each proposal, but as long as the acceptance or rejection of each proposal is done in a way that satisfies detailed balance, and as long as all the different types of proposals, when used together create an irreducible chain around the space, then you get a valid MCMC sampler.

We make a function that looks much like mcmc_2d_mh(), but in which the proposal and acceptance steps for \(f\) and \(p\) are done separately within each sweep. This is going to look a little bit weird because we do each update within the sweep but set the new value of \(f\) in the “next” sweep. (You’ll see below…)

#' function to do MCMC using a component-wise Metropolis-Hastings sampler
#' @param ndata a three-vector (nAA, nAa, naa) of the observed data
#' @param pri a vector of four components: (alpha_f, beta_f, alpha_p, beta_p)
#' @param init a two vector of starting values (f, p).  Each should be within the
#' unit interval.
#' @param sweeps the number of sweeps (i.e proposed changes) to do in the MCMC chain.
#' @param f_sd the standard deviation of the normal distribution for proposing new values to f
#' @param p_sd the standard deviation of the normal distribution for proposing new values to p
#' @return returns a tibble of proposals made, values visited, values of MH ratio, etc
mcmc_cw_mh <- function(ndata, 
                       pri = c(1, 1, 1, 1), 
                       init = c(.2, .5), 
                       sweeps = 500,
                       f_sd = 0.07,
                       p_sd = 0.07) {

  # create vectors in which to store output. Note that we will be storing 
  # the proposed values and the MH-ratio each sweep, too, for later analysis.
  f <- p <- fprop <- pprop <- mh_ratio_f <- mh_ratio_p <- rep(NA_real_, sweeps + 1)
  accepted_f <- accepted_p <- rep(NA, sweeps + 1)
  
  # put initial values in
  f[1] <- init[1]
  p[1] <- init[2]
  
  # then cycle over sweeps
  for (i in 1:sweeps) {
    
    # propose new value for f
    fprop[i] <- rnorm(1, f[i], f_sd)
    
    # compute the hastings ratio with only a change to f proposed
    mh_ratio_f[i] <- exp(log_joint_prob(ndata, fprop[i], p[i], pri) -
      log_joint_prob(ndata, f[i], p[i], pri))
    
    # then accept or reject it
    U <- runif(1)
    if (is.nan(mh_ratio_f[i]) | runif(1) > mh_ratio_f[i]) {# reject!
      accepted_f[i] <- FALSE
      f[i + 1] <- f[i]
    } else {# if accepted, then update the value of f
      accepted_f[i] <- TRUE
      f[i + 1] <- fprop[i] # set the value.  This is a little weird because we are still in sweep i.
    }
    
    # now, the current value of f is stored in f[i + 1], and we propose a new value for p
    pprop[i] <- rnorm(1, p[i], p_sd)
    
     # compute the hastings ratio using the new f and the proposed value of p
    mh_ratio_p[i] <- exp(log_joint_prob(ndata, f[i + 1], pprop[i], pri) -
      log_joint_prob(ndata, f[i + 1], p[i], pri))
    
    
    # and reject or accept the proposal
    if (is.nan(mh_ratio_p[i]) | runif(1) > mh_ratio_p[i]) {# reject!
      accepted_p[i] <- FALSE
      p[i + 1] <- p[i]
    } else {# if not accepted then make p the same as the current p
      accepted_p[i] <- TRUE
      p[i + 1] <- pprop[i]
    }
    
  }
  
  # in the end, make a tibble and return
  tibble(sweep = 1:(sweeps + 1),
         f = f,
         p = p, 
         proposed_f = fprop,
         proposed_p = pprop,
         mh_ratio_f = mh_ratio_f,
         mh_ratio_p = mh_ratio_p,
         accepted_f = accepted_f,
         accepted_p = accepted_p
         )
}

Using the samplers

Each of these Metropolis-Hastings samplers returns output in a tibble. For example:

mcmc_cw_mh(ndata = c(30, 10, 10))

Exercises

  1. Run each of the samplers for 5000 sweeps, with ndata = c(30, 10, 10).
mcmc_run <- list(
  component_wise = mcmc_cw_mh(ndata = c(30, 10, 10), sweeps = 5000),
  two_d_sampler = mcmc_2d_mh(ndata = c(30, 10, 10), sweeps = 5000)
) %>%
  bind_rows(.id = "sampler")
  1. Plot the traces for \(f\) and \(p\) for both the 2-d and the componentwise sampler. Are they visibly different?
# look at the f's
ggplot(mcmc_run, aes(x = sweep, y = f)) +
  geom_line() +
  facet_wrap(~ sampler, nrow = 1)

# look at the p's
ggplot(mcmc_run, aes(x = sweep, y = p)) +
  geom_line() +
  facet_wrap(~ sampler, nrow = 1)

  1. Compare the acceptance rates for \(p\) and \(f\) for both samplers.
mcmc_run %>%
  group_by(sampler) %>%
  summarise(
    f_accept = mean(accepted_f, na.rm = TRUE),
    p_accept = mean(accepted_p, na.rm = TRUE)
  )
  1. In 3 you should have found that the acceptance rate is higher in the component-wise sampler (as expected).

  2. This was a simple exercise in sampling continuous random variables according to a two dimensional posterior surface. Now, imagine that the standard deviations of the proposal distributions for \(p\) and \(f\) are fixed, then, draw (by hand) the level curves (a “contour” plot) of a 2-d posterior surface for which the 2-d sampler might have a higher acceptance rate than the component wide sampler. Draw the standard deviations of the proposal distributions on for scale.

A two dimensional surface that is “tilted” (showing high correlation between f and p). If the standard devation is much greater than the “width” of the posterior, then changes in only f or p would often be rejected

For example:

Review of the model

We are dealing with a very simple model for inbreeding. It is one type of model that might be used to account for an excess of homozygotes in a sample from a population. We assume that we have taken a sample of \(n\) diploid individuals from the population, and we will be considering just a single locus at a time. This locus has two alleles \(A\) and \(a\), and our sample can be summarized by (what turns out to be the sufficient statistic, in this case) the numbers of the three possible genotypes: \(n_{AA}\), the number of \(AA\) homozygotes; \(n_{Aa}\), the number of heterozygotes; and \(n_{aa}\), the number of \(aa\) homozygotes. Of course, \(n_{AA} + n_{Aa} + n_{aa} = n\).

In a population with no inbreeding, the expected fraction of genotypes follows the Hardy-Weinberg equilibrium proportions. Letting \(p\) denote the frequency of the \(A\) allele in the population, under Hardy-Weinberg equilibrium the, expected fractions of the different genotypes are: \[ \begin{aligned} P_\mathrm{HW}(AA) & = p^2 \\ P_\mathrm{HW}(Aa) & = 2p(1-p)\\ P_\mathrm{HW}(aa) & = (1-p)^2 \end{aligned} \]

Basic probabilities

Inbreeding in a population violates one of the many assumptions required for Hardy-Weinberg equilibrium to hold. We model inbreeding here as a property of the pair of gene copies that occur in an individual in the population, and we measure it with the population inbreeding coefficient, \(f\), which can be interpreted as the probability that the pair of gene copies in an individual randomly sampled from the population are identical by descent, or IBD for short. For our purposes in this session, we will take “identical by descent” to mean that they are both copies of the same, recent ancestral gene copy. More important than the exact definition of “identical by descent” adopted here are the consequences for two gene copies of being IBD. And in this case, that is very simple: we will assume that if two gene copies are IBD, then they must also be the same allelic type. In other words, if two gene copies are IBD, and the first of them is allele \(A\), then the second must also be allele \(A\).

So, given the inbreeding coefficient \(f\), we can compute the probability that a randomly sampled individual has the genotype \(AA\), \(Aa\), or \(aa\). First, let us consider \(P(AA)\): with probability \(f\) the two gene copies at a locus in the individual are IBD, in which case only the first gene copy must by \(A\), since the second one will be too. On the other hand, with probability \((1-f)\) the two gene copies at the locus in the individual are not IBD, and so the probability of being \(AA\) is just the standard Hardy-Weinberg probability, \(P_\mathrm{HW}(AA) = p^2\). Hence, under the inbreeding model: \[ \begin{aligned} P(AA) &= fp + (1-f)p^2 \\ P(Aa) &= f\times 0 + (1-f)2p(1-p) \\ P(aa) &= f(1-p) + (1-f)(1-p)^2 \end{aligned} \]

The likelihood

Now recall that our data are \((n_{AA}, n_{Aa}, n_{aa})\)—the numbers of the different genotypes observed in the sample. To move forward in inference, we need to be able to compute the likelihood, which is the probability of our data given the values of the parameters: \(P(n_{AA}, n_{Aa}, n_{aa}|p,f)\). Note here that the two parameters in our model are \(p\), the frequency of the \(A\) allele in the population, and \(f\), the population inbreeding coefficient. We assume that each individual is sampled independently from the population, so the likelihood is a multinomial: \[ P(n_{AA}, n_{Aa}, n_{aa}) = \frac{n!}{n_{AA}! + n_{Aa}! + n_{aa}!}~ [fp + (1-f)p^2]^{n_{AA}}~ [(1-f)2p(1-p)]^{n_{Aa}}~ [f(1-p) + (1-f)(1-p)^2]^{n_{aa}} \] The multinomial coefficient is a constant with respect to \(p\) and \(f\) so it will drop out.

The priors

We need priors of \(p\) and \(f\). These are proportions, so a natural choice is the beta distribution.
Let’s define \(f \sim \mathrm{Beta}(\alpha_f, \beta_f)\) and \(p \sim \mathrm{Beta}(\alpha_p, \beta_p)\), and we will set up our model that way, though the default values we will use are \(\alpha_f = \beta_f = \alpha_p = \beta_p = 1\) which will give us uniform priors for \(f\) and \(p\).

LS0tCnRpdGxlOiAiTUNNQyBTYW1wbGluZyBmb3IgYSBTaW1wbGUgSW5icmVlZGluZyBNb2RlbCAtLSBLRVkiCmRlc2NyaXB0aW9uOiBXZSByZXZpZXcgb3VyIHNpbXBsZSBtb2RlbCBmb3IgaW5icmVlZGluZyBhdCBhIGxvY3VzIGFuZCBkZXZlbG9wIHRoZSBjb2RlIHRvIHBlcmZvcm0gc2V2ZXJhbCBkaWZmZXJlbnQgdHlwZXMgb2YgTWV0cm9wb2xpcy1IYXN0aW5ncyB1cGRhdGVzLCB0aGVuIGF1Z21lbnQgdGhlIG1vZGVsIHRvIGluY2x1ZGUgbGF0ZW50IHZhcmlhYmxlcyB0aGF0IGxldCB1cyBlYXNpbHkgdG8gR2liYnMtc2FtcGxpbmcgdXBkYXRlcy4Kb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKLS0tCgpcdXNlcGFja2FnZXtibGthcnJheX0KXHVzZXBhY2thZ2V7YW1zbWF0aH0KXG5ld2NvbW1hbmR7XGJtfXtcYm9sZHN5bWJvbH0KXG5ld2NvbW1hbmR7XEV4cH17XG1hdGhiYmJ7RX19CgpUaGlzIGlzIGFuIFItY29kZSBjb21wYW5pb24gdG8gU2Vzc2lvbiA3LCBhbmQgdGhlIGNvbnRlbnRzIGhlcmUgZW5jb21wYXNzIGp1c3QgYWJvdXQgCmFsbCB0aGUgbWF0ZXJpYWwgaW4gdGhhdCBzZXNzaW9uLiAgRHVyaW5nIHRoZSBsZWN0dXJlIGFzc29jaWF0ZWQgd2l0aCB0aGUgbGVzc29uLAp3ZSBzaG93ZWQgc29tZSBPcGVuR0wtYmFzZWQgYW5pbWF0aW9ucyBvZiB0aGUgTUNNQyBzYW1wbGVyIGZvciB0aGUgaW5icmVlZGluZyBtb2RlbCwKYnV0IHRoZSBjb2RlIGZvciB0aGF0IGlzIGltcGxlbWVudGVkIGluIEMsIGFuZCBpcyBub3Qgc3VwZXIgYWNjZXNzaWJsZS4gIFNvLCB0aGUgZ29hbApoZXJlIGlzIHRvIGltcGxlbWVudCwgaW4gUiwgdGhlIG1vZGVsIGFuZCBNQ01DIGZvciB0aGUgbW9kZWwgdXNpbmcgdGhlIHNldmVyYWwgZGlmZmVyZW50CnR5cGVzIG9mIHNhbXBsZXJzIGRpc2N1c3NlZCBpbiB0aGUgc2Vzc2lvbi4gIAoKTGV0J3MgbG9hZCBIYWRsZXkncyB0aWR5dmVyc2UgYW5kIG90aGVyIHBhY2thZ2VzIHdlIG5lZWQgYmVmb3JlIHdlIGdldCBnb2luZy4gIFRoZSBmb2xsb3dpbmcKd2lsbCBhbHNvIGluc3RhbGwgdGhlbSBpZiB5b3UgZG9uJ3QgaGF2ZSB0aGVtLiAKYGBge3IsIG1lc3NhZ2U9RkFMU0V9CnBhY2tzIDwtIGMoInRpZHl2ZXJzZSIsICJwbG90bHkiLCAidmlyaWRpcyIsICJicm9vbSIpCgojIGluc3RhbGwgYW55IHRoYXQgYXJlIG5vdCBoZXJlCmluc3RhbGxfZW0gPC0gc2V0ZGlmZihwYWNrcywgcm93bmFtZXMoaW5zdGFsbGVkLnBhY2thZ2VzKCkpKQppZiAobGVuZ3RoKGluc3RhbGxfZW0pID4gMCkgaW5zdGFsbC5wYWNrYWdlcyhwa2dzID0gaW5zdGFsbF9lbSkKCiMgbG9hZCBlbSB1cApkdW1wIDwtIGxhcHBseShwYWNrcywgZnVuY3Rpb24oeCkgbGlicmFyeSh4LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKQpgYGAKCgojIyBUaGUgam9pbnQgcHJvYmFiaWxpdHkKCkFzIGRpc2N1c3NlZCBpbiB0aGUgcHJldmlvdXMgc2Vzc2lvbiwgdGhpcyBpcyBqdXN0IHRoZSBwcm9kdWN0IG9mIHRoZSBwcmlvcnMgYW5kIHRoZSBsaWtlbGlob29kcy4gIEluIGl0cyBmdWxsIGdsb3J5LCBpdCBsb29rcyBsaWtlLiAgKEZvciBhIHJldmlldyBvZiBob3cgdGhhdCBqb2ludCBkZW5zaXR5IHdhcyBkZXZlbG9wZWQsIHNlZQpbdGhlIGRpc2N1c3Npb24gYXQgdGhlIHZlcnkgZW5kXSgjcmV2aWV3KQokJApcYmVnaW57YWxpZ25lZH0KUChuX3tBQX0sIG5fe0FhfSwgbl97YWF9LCBmLCBwIHwgXGFscGhhX2YsIFxiZXRhX2YsIFxhbHBoYV9wLCBcYmV0YV9wKSAmID0gClxmcmFje1xHYW1tYShcYWxwaGFfZiArIFxiZXRhX2YpfXtcR2FtbWEoXGFscGhhX2YpXEdhbW1hKFxiZXRhX2YpfWZee1xhbHBoYV9mIC0gMX0oMS1mKV57XGJldGFfZiAtIDF9ClxmcmFje1xHYW1tYShcYWxwaGFfcCArIFxiZXRhX3ApfXtcR2FtbWEoXGFscGhhX3ApXEdhbW1hKFxiZXRhX3ApfXBee1xhbHBoYV9wIC0gMX0oMS1wKV57XGJldGFfcCAtIDF9IFx0aW1lcyBcXAomIFxmcmFje24hfXtuX3tBQX0hICsgbl97QWF9ISArIG5fe2FhfSF9fgpbZnAgKyAoMS1mKXBeMl1ee25fe0FBfX1+ClsoMS1mKTJwKDEtcCldXntuX3tBYX19fgpbZigxLXApICsgKDEtZikoMS1wKV4yXV57bl97YWF9fQpcZW5ke2FsaWduZWR9CiQkCldlIHdpbGwgYmUgdXNpbmcgdGhpcyBpbiAKTUNNQyBpbiB3aGljaCB0aGUgdGhlIGh5cGVycHJpb3JzICQoXGFscGhhX2YsIFxiZXRhX2YsIFxhbHBoYV9wLCBcYmV0YV9wKSQgYW5kIHRoZSBkYXRhIGFyZSBmaXhlZC4KVGh1cyB0aGUgdGVybXMgKGZhY3RvcnMpIHRoYXQgaW52b2x2ZSBfb25seV8gdGhlIGRhdGEgYW5kIHRoZSBoeXBlcnByaW9ycyBhcmUgY29uc3RhbnRzIHRoYXQgd2lsbCBkcm9wCm91dCBvZiB0aGUgSGFzdGluZ3MgcmF0aW8sIHNvIHRoZXkgY2FuIGJlIHNhZmVseSBpZ25vcmVkLiAgU28sIG91ciBqb2ludCBwcm9iYWJpbGl0eSBjYW4gYmUgY29tcHV0ZWQKYXMgc29tZXRoaW5nIHRoYXQgbG9va3MgbGlrZToKJCQKXGJlZ2lue2FsaWduZWR9ClAobl97QUF9LCBuX3tBYX0sIG5fe2FhfSwgZiwgcCB8IFxhbHBoYV9mLCBcYmV0YV9mLCBcYWxwaGFfcCwgXGJldGFfcCkgJiBccHJvcHRvIApmXntcYWxwaGFfZiAtIDF9KDEtZilee1xiZXRhX2YgLSAxfQpwXntcYWxwaGFfcCAtIDF9KDEtcClee1xiZXRhX3AgLSAxfSBcdGltZXMgXFwKJiB+fn5+W2ZwICsgKDEtZilwXjJdXntuX3tBQX19fgpbKDEtZikycCgxLXApXV57bl97QWF9fX4KW2YoMS1wKSArICgxLWYpKDEtcCleMl1ee25fe2FhfX0KXGVuZHthbGlnbmVkfQokJApXZSB3aWxsIGltcGxlbWVudCB0aGlzIGluIGEgZnVuY3Rpb24gdGhhdCByZXR1cm5zIHRoZSBfbG9nXyBvZiB0aGUgYWJvdmUgcXVhbnRpdHkKc28gdGhhdCB3ZSB3b24ndCBydW4gaW50byB1bmRlcmZsb3cgaXNzdWVzIHdpdGggdmVyeSBsYXJnZSBzYW1wbGVzOgpgYGB7ciBqb2ludH0KIycgdGhlIGxvZyBvZiB0aGUgam9pbnQgcHJvYmFiaWxpdHkgb2YgYWxsIHRoZSBkYXRhIGFuZCBwYXJhbWF0ZXJzIGdpdmVuIHRoZSBwcmlvcnMKIycKIycgVGhpcyBpcyBjb21wdXRlZCBoYXZpbmcgZHJvcHBlZCBhbGwgdGhlIGNvbnN0YW50IGZhY3RvcnMgaW4gdGhlIHByb2JhYmlsaXR5LgojJyBAcGFyYW0gbiBhIHZlY3RvciBvZiB0aHJlZSBlbGVtZW50czogKG5BQSwgbkFhLCBuYWEpLCB0aGUgbnVtYmVyIG9mIEFBJ3MsIHRoZQojJyBudW1iZXIgb2YgQWEncywgYW5kIHRoZSBudW1iZXIgb2YgYWEncwojJyBAcGFyYW0gZiB0aGUgaW5icmVlZGluZyBjb2VmZmllbnQKIycgQHBhcmFtIHAgdGhlIGZyZXF1ZW5jeSBvZiB0aGUgQSBhbGxlbGUKIycgQHBhcmFtIHByaSBhIHZlY3RvciBvZiBmb3VyIGNvbXBvbmVudHM6IChhbHBoYV9mLCBiZXRhX2YsIGFscGhhX3AsIGJldGFfcCkgd2hpY2ggYXJlIHRoZSAKIycgYmV0YSBwYXJhbWV0ZXJzIGZvciB0aGUgcHJpb3JzIG9uIGYgYW5kIHAuICBCeSBkZWZhdWx0IHRoZXkgYXJlIGFsbCAxLgpsb2dfam9pbnRfcHJvYiA8LSBmdW5jdGlvbihuLCBmLCBwLCBwcmkgPSBjKDEsIDEsIDEsIDEpKSB7CiAgIyBub3QgZ29pbmcgdG8gZG8gbXVjaCBlcnJvciBjaGVja2luZyBoZXJlCiAgCiAgIyBjb21wdXRlIHRoZSByYXcgdmFsdWVzLCBhbnl0aGluZyBvdXRzaWRlIG9mIHRoZSB1bml0IGludGVydmFsIHdlIHdpbGwgc2VuZAogICMgYmFjayBhcyBOYU4KICBpZmVsc2UoZiA8PSAwIHwgZiA+PSAxIHwgcCA8PSAwIHwgcCA+PSAxLCBOYU4sCiAgICAgICAgIGxvZyhmKSAqIChwcmlbMV0gLSAxKSArIAogICAgICAgICAgIGxvZygxIC0gZikgKiAocHJpWzJdIC0gMSkgKwogICAgICAgICAgIGxvZyhwKSAqIChwcmlbM10gLSAxKSArCiAgICAgICAgICAgbG9nKDEgLSBwKSAqIChwcmlbNF0gLSAxKSArCiAgICAgICAgICAgbG9nKGYgKiBwICsgKDEgLSBmKSAqIHAgXiAyKSAqIG5bMV0gKwogICAgICAgICAgIGxvZygoMSAtIGYpICogMiAqIHAgKiAoMSAtIHApKSAqIG5bMl0gKyAKICAgICAgICAgICBsb2coZiAqICgxIC0gcCkgKyAoMSAtIGYpICogKDEgLSBwKSBeIDIpICogblszXSkKICAKICAKCn0KYGBgCk5vdGUgdGhhdCB0aGlzIGZ1bmN0aW9uIGlzIHZlY3Rvcml6ZWQgb3ZlciAkZiQgYW5kICRwJCwgYnV0IG5vdCAkbiQgb3IgdGhlIHByaW9ycy4KCgojIyMgQSAzLUQgcGxvdAoKV2UgY2FuIGNvbXB1dGUgdGhlIGpvaW50IHByb2JhYmlsaXR5IG9mIGFsbCB0aGUgdmFyaWFibGVzIGVhc2lseSwgYW5kLCBiZWNhdXNlIHRoaXMgaXMgYSB0b3kgcHJvYmxlbSAKaW4gdHdvIGRpbWVuc2lvbnMsIHdlIGNhbiB2aXN1YWxpemUgcm91Z2hseSB3aGF0IHRoZSBwb3N0ZXJpb3Igc3VyZmFjZSB3aWxsIGxvb2sgbGlrZSBieSAKY29tcHV0aW5nIHZhbHVlcyBvbiBhIGdyaWQgYW5kIG5vcm1hbGl6aW5nIHRob3NlIHZhbHVlcyBzbyB0aGV5IHN1bSB0byBvbmUuICBMZXQncyBkbyB0aGF0LCBzaW5jZQppdCBpcyBhIGdvb2QgY2hhbmNlIHRvIGludHJvZHVjZSB0aGUgW3Bsb3RseV0oaHR0cHM6Ly9wbG90Lmx5L3IvKSBwYWNrYWdlIHRvIGFueW9uZSB0aGF0IG1pZ2h0IG5vdCB5ZXQga25vdyBpdC4KClNvLCBsZXQncyB0YWtlIHRoZSBleGFtcGxlIGZyb20gdGhlIGxlY3R1cmUgYW5kIHNldCBvdXIgZGF0YSB0byBiZSAkbl97QUF9ID0gMzAkLCAkbl97QWF9ID0gMTAkLCBhbmQgCiRuX3thYX0gPSAxMCQuICBUaG9zZSBhcmUgdGhlIGV4cGVjdGVkIHZhbHVlcyBpZiAkZiA9IDAuNSQgYW5kICRwID0gMC43JCwKYGBge3J9Cm5kYXRhIDwtIGMoMzAsIDEwLCAxMCkKYGBgCmFuZCB0aGVuIGNvbXB1dGUgdGhlIGxvZyBwcm9iLCBleHBvbmVudGlhdGUgaXQsIGFuZCBub3JtYWxpemUgaXQgb3ZlciBhIGdyaWQgb2YgdmFsdWUgZm9yCiRmJCBhbmQgJHAkOgpgYGB7cn0KZl92YWxzIDwtIHNlcSgwLCAxLCBieSA9IDAuMDMpCnBfdmFscyA8LSBzZXEoMCwgMSwgYnkgPSAwLjAzKQoKIyBtYWtlIGEgdGlkeSB0aWJibGUgb2YgdmFsdWVzIApncmlkX3ZhbHMgPC0gZXhwYW5kLmdyaWQoZiA9IGZfdmFscywgcCA9IHBfdmFscykgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgbXV0YXRlKGpvaW50ID0gZXhwKGxvZ19qb2ludF9wcm9iKG5kYXRhLCBmLCBwKSkpICU+JQogIG11dGF0ZShub3JtX2pvaW50ID0gam9pbnQgLyBzdW0oam9pbnQsIG5hLnJtID0gVFJVRSkpICU+JQogIHNlbGVjdCgtam9pbnQpCgojIHRoZW4gcHV0IHRob3NlIHZhbHVlcyBpbnRvIGEgbWF0cml4LCB3aXRoIHJvd3MgY29ycmVzcG9uZGluZyB0byBmIGFuZCBjb2xzIHRvIHAKcHJvYnMgPC0gbWF0cml4KGdyaWRfdmFscyRub3JtX2pvaW50LCBucm93ID0gbGVuZ3RoKGZfdmFscyksIG5jb2wgPSBsZW5ndGgocF92YWxzKSkKCmBgYApOb3cgd2UgY2FuIHBsb3QgaXQgd2l0aCBwbG90bHk6CmBgYHtyLCBmaWcud2lkdGg9OH0KcGxvdF9seSh4ID0gfnBfdmFscywgeSA9IH5mX3ZhbHMsIHogPSB+cHJvYnMpICU+JQogIGFkZF9zdXJmYWNlKCkKYGBgCgpUcnkgaW50ZXJhY3Rpbmcgd2l0aCB0aGF0IHBsb3QsIGVzcGVjaWFsbHkgaWYgeW91IGFyZSBub3QgZmFtaWxpYXIgd2l0aCBwbG90bHkuICBZb3UgY2FuIHpvb20sIHBhbiwgYW5kCnJldm9sdmUgaXQsIGFuZCB5b3UgY2FuIGFsc28gbG9vayBhdCBpbmRpdmlkdWFsIHZhbHVlcyBieSBtb3VzaW5nIG92ZXIgd2l0aGluIHRoZSBwbG90LgoKIyMgIjItRCIgTWV0cm9wb2xpcy1IYXN0aW5ncyBTYW1wbGVyCgpXZSBub3cgc3RhcnQgb3VyIGZvcmF5cyBpbnRvIGRpZmZlcmVudCBNQ01DIHNhbXBsZXJzLCByb3VnaGx5IGZvbGxvd2luZyB0aGUgbGVjdHVyZSBub3RlcyBmcm9tIHRoZSBzZXNzaW9uLiAKVGhlIGZpcnN0IGlzIGEgc2FtcGxlciBpbiB3aGljaCB3ZSBwcm9wb3NlIGNoYW5nZXMgdG8gYm90aCAkZiQgYW5kICRwJCBhbmQgdGhlbiB3ZSBhY2NlcHQgb3IgcmVqZWN0IGJvdGggb2YgdGhvc2UKcHJvcG9zYWxlZCBjaGFuZ2VzLCB0b2dldGhlciwgaW4gb25lIGZlbGwgc3dvb3AsIGFjY29yZGluZyB0byB0aGUgSGFzdGluZ3MgUmF0aW8uCgpGb3Igb3VyIHByb3Bvc2FscyBpbiB0aGlzIGNhc2Ugd2Ugd2lsbCB1c2UgdHdvIGluZGVwZW5kZW50LCBzeW1tbWV0cmljYWwgbm9ybWFsIGRpc3RyaWJ1dGlvbnMgY2VudGVyZWQKb24gdGhlIGN1cnJlbnQgdmFsdWVzLiAgV2Ugd2lsbCB3cmFwIHVwIHRoZSB3aG9sZSBwcm9jZXNzIGluIGEgc2luZ2xlIGZ1bmN0aW9uCmNhbGxlZCBgbWNtY18yZF9taCgpYC4KYGBge3J9CiMnIGZ1bmN0aW9uIHRvIGRvIE1DTUMgdXNpbmcgYSAiMi1EIiBNZXRyb3BvbGlzLUhhc3RpbmdzIHNhbXBsZXIKIycgQHBhcmFtIG5kYXRhIGEgdGhyZWUtdmVjdG9yIChuQUEsIG5BYSwgbmFhKSBvZiB0aGUgb2JzZXJ2ZWQgZGF0YQojJyBAcGFyYW0gcHJpIGEgdmVjdG9yIG9mIGZvdXIgY29tcG9uZW50czogKGFscGhhX2YsIGJldGFfZiwgYWxwaGFfcCwgYmV0YV9wKQojJyBAcGFyYW0gaW5pdCBhIHR3byB2ZWN0b3Igb2Ygc3RhcnRpbmcgdmFsdWVzIChmLCBwKS4gIEVhY2ggc2hvdWxkIGJlIHdpdGhpbiB0aGUKIycgdW5pdCBpbnRlcnZhbC4KIycgQHBhcmFtIHN3ZWVwcyB0aGUgbnVtYmVyIG9mIHN3ZWVwcyAoaS5lIHByb3Bvc2VkIGNoYW5nZXMpIHRvIGRvIGluIHRoZSBNQ01DIGNoYWluLgojJyBAcGFyYW0gZl9zZCB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uIGZvciBwcm9wb3NpbmcgbmV3IHZhbHVlcyB0byBmCiMnIEBwYXJhbSBwX3NkIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIG5vcm1hbCBkaXN0cmlidXRpb24gZm9yIHByb3Bvc2luZyBuZXcgdmFsdWVzIHRvIHAKIycgQHJldHVybiByZXR1cm5zIGEgdGliYmxlIG9mIHByb3Bvc2FscyBtYWRlLCB2YWx1ZXMgdmlzaXRlZCwgdmFsdWVzIG9mIE1IIHJhdGlvLCBldGMKbWNtY18yZF9taCA8LSBmdW5jdGlvbihuZGF0YSwgCiAgICAgICAgICAgICAgICAgICAgICAgcHJpID0gYygxLCAxLCAxLCAxKSwgCiAgICAgICAgICAgICAgICAgICAgICAgaW5pdCA9IGMoLjIsIC41KSwgCiAgICAgICAgICAgICAgICAgICAgICAgc3dlZXBzID0gNTAwLAogICAgICAgICAgICAgICAgICAgICAgIGZfc2QgPSAwLjA3LAogICAgICAgICAgICAgICAgICAgICAgIHBfc2QgPSAwLjA3KSB7CgogICMgY3JlYXRlIHZlY3RvcnMgaW4gd2hpY2ggdG8gc3RvcmUgb3V0cHV0LiBOb3RlIHRoYXQgd2Ugd2lsbCBiZSBzdG9yaW5nIAogICMgdGhlIHByb3Bvc2VkIHZhbHVlcyBhbmQgdGhlIE1ILXJhdGlvIGVhY2ggc3dlZXAsIHRvbywgZm9yIGxhdGVyIGFuYWx5c2lzLgogIGYgPC0gcCA8LSBmcHJvcCA8LSBwcHJvcCA8LSBtaF9yYXRpbyA8LSByZXAoTkFfcmVhbF8sIHN3ZWVwcyArIDEpCiAgYWNjZXB0ZWRfZiA8LSBhY2NlcHRlZF9wIDwtIHJlcChOQSwgc3dlZXBzICsgMSkKICAKICAjIHB1dCBpbml0aWFsIHZhbHVlcyBpbgogIGZbMV0gPC0gaW5pdFsxXQogIHBbMV0gPC0gaW5pdFsyXQogIAogICMgdGhlbiBjeWNsZSBvdmVyIHN3ZWVwcwogIGZvciAoaSBpbiAxOnN3ZWVwcykgewogICAgCiAgICAjIHByb3Bvc2UgbmV3IHZhbHVlcwogICAgZnByb3BbaV0gPC0gcm5vcm0oMSwgZltpXSwgZl9zZCkKICAgIHBwcm9wW2ldIDwtIHJub3JtKDEsIHBbaV0sIHBfc2QpCiAgICAKICAgICMgY29tcHV0ZSB0aGUgaGFzdGluZ3MgcmF0aW8KICAgICMgdGhlIGxvZyBNLUggcmF0aW8gaXMgdGhlIGRpZmZlcmVuY2Ugb2YgdGhlIGxvZyBqb2ludCBwcm9icy4KICAgICMgc2luY2UgdGhlIHByb3Bvc2FsIGRpc3RyaWJ1dGlvbnMgYXJlIHN5bW1ldHJpY2FsIHRoZXkgZHJvcCBvdXQgb2YgdGhlIHJhdGlvLgogICAgbWhfcmF0aW9baV0gPC0gZXhwKGxvZ19qb2ludF9wcm9iKG5kYXRhLCBmcHJvcFtpXSwgcHByb3BbaV0sIHByaSkgLQogICAgICBsb2dfam9pbnRfcHJvYihuZGF0YSwgZltpXSwgcFtpXSwgcHJpKSkKICAgIAogICAgIyBub3csIGlmIG1oX3JhdGlvW2ldIGlzIE5hTiBpdCBtZWFucyB0aGF0IGYgb3IgcCB3YXMgcHJvcG9zZWQgb3V0c2lkZSBvZiB0aGUgdW5pdCBpbnRlcnZhbAogICAgIyBhbmQgaXQgc2hvdWxkIGJlIHJlamVjdGVkIGltbWVkaWF0ZWx5LiAgSWYgbm90LCB0aGVuIHdlIHNpbXVsYXRlIGEgdW5pZm9ybSBSLlYuIG9uICgwLCAxKQogICAgIyBhbmQgcmVqZWN0IHRoZSBwcm9wb3NhbCBpZiB0aGF0IG51bWJlciBpcyBncmVhdGVyIHRoYW4gdGhlIE1ILXJhdGlvLgogICAgaWYgKGlzLm5hbihtaF9yYXRpb1tpXSkgfHwgcnVuaWYoMSkgPiBtaF9yYXRpb1tpXSkgeyMgcmVqZWN0IQogICAgICBhY2NlcHRlZF9mW2ldIDwtIEZBTFNFCiAgICAgIGFjY2VwdGVkX3BbaV0gPC0gRkFMU0UKICAgICAgZltpICsgMV0gPC0gZltpXQogICAgICBwW2kgKyAxXSA8LSBwW2ldCiAgICB9IGVsc2UgeyMgYWNjZXB0IQogICAgICBhY2NlcHRlZF9mW2ldIDwtIFRSVUUKICAgICAgYWNjZXB0ZWRfcFtpXSA8LSBUUlVFCiAgICAgIGZbaSArIDFdIDwtIGZwcm9wW2ldCiAgICAgIHBbaSArIDFdIDwtIHBwcm9wW2ldCiAgICB9CiAgICAKICB9CiAgCiAgIyBpbiB0aGUgZW5kLCBtYWtlIGEgdGliYmxlIGFuZCByZXR1cm4KICB0aWJibGUoc3dlZXAgPSAxOihzd2VlcHMgKyAxKSwKICAgICAgICAgZiA9IGYsCiAgICAgICAgIHAgPSBwLCAKICAgICAgICAgcHJvcG9zZWRfZiA9IGZwcm9wLAogICAgICAgICBwcm9wb3NlZF9wID0gcHByb3AsCiAgICAgICAgIG1oX3JhdGlvID0gbWhfcmF0aW8sCiAgICAgICAgIGFjY2VwdGVkX2YgPSBhY2NlcHRlZF9mLAogICAgICAgICBhY2NlcHRlZF9wID0gYWNjZXB0ZWRfcAogICAgICAgICApCn0KYGBgCgoqKkEgYnJpZWYgbm90ZToqKiBJbiB0aGUgYWJvdmUgZnVuY3Rpb24gKGFuZCB0aGUgb25lIGZvbGxvd2luZykgd2UgYXJlIGJlaW5nIGNhcmVmdWwgdG8gcmVjb3JkCm5vdCBqdXN0IHRoZSBjdXJyZW50IHN0YXRlIG9mIHRoZSBjaGFpbiwgYnV0IGFsc28KZXZlcnkgX3Byb3Bvc2VkXyB2YWx1ZS4gIFR5cGljYWxseSB0aGlzIGlzIG5vdCBkb25lIGluIE1DTUMuICBSYXRoZXIsIGl0IGlzIG1vcmUgdXN1YWwgdG8gc2ltcGx5CnJlY29yZCB0aGUgc3RhdGUgb2YgdGhlIGNoYWluIGF0IGVhY2ggc3dlZXAgKG9yIGF0IHNvbWUgInRoaW5uZWQiIGludGVydmFsIG9mIHN3ZWVwcykuIEhvd2V2ZXIKd2Ugd2FudGVkIHRvIGtlZXAgYSBmdWxsIHJlY29yZCBvZiB0aGUgcHJvZ3Jlc3Npb24gb2YgYWxsIHRoZSB2YXJpYWJsZXMgc28gdGhhdCB0aGV5IHdvdWxkIGJlCmF2YWlsYWJsZSBmb3IgIHN0dWRlbnRzIHRvIHBlcnVzZSBvciBhbmFseXplLiAKCgojIyBDb21wb25lbnQtd2lzZSBNZXRyb3BvbGlzLUhhc3RpbmdzIFNhbXBsZXIKClJhdGhlciB0aGFuIHByb3Bvc2luZyBjaGFuZ2VzIHRvIGJvdGggJGYkIGFuZCAkcCQgYmVmb3JlIGFjY2VwdGluZyBvciByZWplY3RpbmcgdGhlbSwKd2UgY2FuIHByb3Bvc2UganVzdCBhIGNoYW5nZSB0byAkZiQgKHNheSkgYW5kIGFjY2VwdCBvciByZWplY3QgdGhlIHByb3Bvc2FsLCBhbmQgdGhlbiBwcm9wb3NlIGp1c3QgYSBjaGFuZ2UKdG8gJHAkLCBhbmQgdGhlbiBhY2NlcHQgb3IgcmVqZWN0IHRoYXQuICBUaGlzIGlzIGNhbGxlZCBjb21wb25lbnQtd2lzZSBNZXRyb3BvbGlzLUhhc3RpbmdzIHNhbXBsaW5nLiAKVW5kZXJseWluZyBpdCBpcyBhIGNlbnRyYWwgdGhlbWUgaW4gTUNNQywgd2hpY2ggaXMgdGhhdCBqdXN0IG9uZSBvciBhIGZldyBkaW1lbnNpb25zIGNhbiBiZSBjaGFuZ2VkCndpdGggZWFjaCBwcm9wb3NhbCwgYnV0IGFzIGxvbmcgYXMgdGhlIGFjY2VwdGFuY2Ugb3IgcmVqZWN0aW9uIG9mIGVhY2ggcHJvcG9zYWwgaXMgZG9uZSBpbgphIHdheSB0aGF0IHNhdGlzZmllcyBkZXRhaWxlZCBiYWxhbmNlLCBfYW5kXyBhcyBsb25nIGFzIGFsbCB0aGUgZGlmZmVyZW50IHR5cGVzIG9mIHByb3Bvc2FscywKd2hlbiB1c2VkIHRvZ2V0aGVyIGNyZWF0ZSBhbiBpcnJlZHVjaWJsZSBjaGFpbiBhcm91bmQgdGhlIHNwYWNlLCB0aGVuIHlvdSBnZXQgYSB2YWxpZCBNQ01DIHNhbXBsZXIuCgpXZSBtYWtlIGEgZnVuY3Rpb24gdGhhdCBsb29rcyBtdWNoIGxpa2UgYG1jbWNfMmRfbWgoKWAsIGJ1dCBpbiB3aGljaCB0aGUgcHJvcG9zYWwgYW5kIGFjY2VwdGFuY2Ugc3RlcHMKZm9yICRmJCBhbmQgJHAkIGFyZSBkb25lIHNlcGFyYXRlbHkgd2l0aGluIGVhY2ggc3dlZXAuIFRoaXMgaXMgZ29pbmcgdG8gbG9vayBhIGxpdHRsZSBiaXQgd2VpcmQKYmVjYXVzZSB3ZSBkbyBlYWNoIHVwZGF0ZSB3aXRoaW4gdGhlIHN3ZWVwIGJ1dCBzZXQgdGhlIG5ldyB2YWx1ZSBvZiAkZiQgaW4gdGhlICJuZXh0IiBzd2VlcC4KKFlvdSdsbCBzZWUgYmVsb3cuLi4pCmBgYHtyfQojJyBmdW5jdGlvbiB0byBkbyBNQ01DIHVzaW5nIGEgY29tcG9uZW50LXdpc2UgTWV0cm9wb2xpcy1IYXN0aW5ncyBzYW1wbGVyCiMnIEBwYXJhbSBuZGF0YSBhIHRocmVlLXZlY3RvciAobkFBLCBuQWEsIG5hYSkgb2YgdGhlIG9ic2VydmVkIGRhdGEKIycgQHBhcmFtIHByaSBhIHZlY3RvciBvZiBmb3VyIGNvbXBvbmVudHM6IChhbHBoYV9mLCBiZXRhX2YsIGFscGhhX3AsIGJldGFfcCkKIycgQHBhcmFtIGluaXQgYSB0d28gdmVjdG9yIG9mIHN0YXJ0aW5nIHZhbHVlcyAoZiwgcCkuICBFYWNoIHNob3VsZCBiZSB3aXRoaW4gdGhlCiMnIHVuaXQgaW50ZXJ2YWwuCiMnIEBwYXJhbSBzd2VlcHMgdGhlIG51bWJlciBvZiBzd2VlcHMgKGkuZSBwcm9wb3NlZCBjaGFuZ2VzKSB0byBkbyBpbiB0aGUgTUNNQyBjaGFpbi4KIycgQHBhcmFtIGZfc2QgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbiBmb3IgcHJvcG9zaW5nIG5ldyB2YWx1ZXMgdG8gZgojJyBAcGFyYW0gcF9zZCB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uIGZvciBwcm9wb3NpbmcgbmV3IHZhbHVlcyB0byBwCiMnIEByZXR1cm4gcmV0dXJucyBhIHRpYmJsZSBvZiBwcm9wb3NhbHMgbWFkZSwgdmFsdWVzIHZpc2l0ZWQsIHZhbHVlcyBvZiBNSCByYXRpbywgZXRjCm1jbWNfY3dfbWggPC0gZnVuY3Rpb24obmRhdGEsIAogICAgICAgICAgICAgICAgICAgICAgIHByaSA9IGMoMSwgMSwgMSwgMSksIAogICAgICAgICAgICAgICAgICAgICAgIGluaXQgPSBjKC4yLCAuNSksIAogICAgICAgICAgICAgICAgICAgICAgIHN3ZWVwcyA9IDUwMCwKICAgICAgICAgICAgICAgICAgICAgICBmX3NkID0gMC4wNywKICAgICAgICAgICAgICAgICAgICAgICBwX3NkID0gMC4wNykgewoKICAjIGNyZWF0ZSB2ZWN0b3JzIGluIHdoaWNoIHRvIHN0b3JlIG91dHB1dC4gTm90ZSB0aGF0IHdlIHdpbGwgYmUgc3RvcmluZyAKICAjIHRoZSBwcm9wb3NlZCB2YWx1ZXMgYW5kIHRoZSBNSC1yYXRpbyBlYWNoIHN3ZWVwLCB0b28sIGZvciBsYXRlciBhbmFseXNpcy4KICBmIDwtIHAgPC0gZnByb3AgPC0gcHByb3AgPC0gbWhfcmF0aW9fZiA8LSBtaF9yYXRpb19wIDwtIHJlcChOQV9yZWFsXywgc3dlZXBzICsgMSkKICBhY2NlcHRlZF9mIDwtIGFjY2VwdGVkX3AgPC0gcmVwKE5BLCBzd2VlcHMgKyAxKQogIAogICMgcHV0IGluaXRpYWwgdmFsdWVzIGluCiAgZlsxXSA8LSBpbml0WzFdCiAgcFsxXSA8LSBpbml0WzJdCiAgCiAgIyB0aGVuIGN5Y2xlIG92ZXIgc3dlZXBzCiAgZm9yIChpIGluIDE6c3dlZXBzKSB7CiAgICAKICAgICMgcHJvcG9zZSBuZXcgdmFsdWUgZm9yIGYKICAgIGZwcm9wW2ldIDwtIHJub3JtKDEsIGZbaV0sIGZfc2QpCiAgICAKICAgICMgY29tcHV0ZSB0aGUgaGFzdGluZ3MgcmF0aW8gd2l0aCBvbmx5IGEgY2hhbmdlIHRvIGYgcHJvcG9zZWQKICAgIG1oX3JhdGlvX2ZbaV0gPC0gZXhwKGxvZ19qb2ludF9wcm9iKG5kYXRhLCBmcHJvcFtpXSwgcFtpXSwgcHJpKSAtCiAgICAgIGxvZ19qb2ludF9wcm9iKG5kYXRhLCBmW2ldLCBwW2ldLCBwcmkpKQogICAgCiAgICAjIHRoZW4gYWNjZXB0IG9yIHJlamVjdCBpdAogICAgVSA8LSBydW5pZigxKQogICAgaWYgKGlzLm5hbihtaF9yYXRpb19mW2ldKSB8IHJ1bmlmKDEpID4gbWhfcmF0aW9fZltpXSkgeyMgcmVqZWN0IQogICAgICBhY2NlcHRlZF9mW2ldIDwtIEZBTFNFCiAgICAgIGZbaSArIDFdIDwtIGZbaV0KICAgIH0gZWxzZSB7IyBpZiBhY2NlcHRlZCwgdGhlbiB1cGRhdGUgdGhlIHZhbHVlIG9mIGYKICAgICAgYWNjZXB0ZWRfZltpXSA8LSBUUlVFCiAgICAgIGZbaSArIDFdIDwtIGZwcm9wW2ldICMgc2V0IHRoZSB2YWx1ZS4gIFRoaXMgaXMgYSBsaXR0bGUgd2VpcmQgYmVjYXVzZSB3ZSBhcmUgc3RpbGwgaW4gc3dlZXAgaS4KICAgIH0KICAgIAogICAgIyBub3csIHRoZSBjdXJyZW50IHZhbHVlIG9mIGYgaXMgc3RvcmVkIGluIGZbaSArIDFdLCBhbmQgd2UgcHJvcG9zZSBhIG5ldyB2YWx1ZSBmb3IgcAogICAgcHByb3BbaV0gPC0gcm5vcm0oMSwgcFtpXSwgcF9zZCkKICAgIAogICAgICMgY29tcHV0ZSB0aGUgaGFzdGluZ3MgcmF0aW8gdXNpbmcgdGhlIG5ldyBmIGFuZCB0aGUgcHJvcG9zZWQgdmFsdWUgb2YgcAogICAgbWhfcmF0aW9fcFtpXSA8LSBleHAobG9nX2pvaW50X3Byb2IobmRhdGEsIGZbaSArIDFdLCBwcHJvcFtpXSwgcHJpKSAtCiAgICAgIGxvZ19qb2ludF9wcm9iKG5kYXRhLCBmW2kgKyAxXSwgcFtpXSwgcHJpKSkKICAgIAogICAgCiAgICAjIGFuZCByZWplY3Qgb3IgYWNjZXB0IHRoZSBwcm9wb3NhbAogICAgaWYgKGlzLm5hbihtaF9yYXRpb19wW2ldKSB8IHJ1bmlmKDEpID4gbWhfcmF0aW9fcFtpXSkgeyMgcmVqZWN0IQogICAgICBhY2NlcHRlZF9wW2ldIDwtIEZBTFNFCiAgICAgIHBbaSArIDFdIDwtIHBbaV0KICAgIH0gZWxzZSB7IyBpZiBub3QgYWNjZXB0ZWQgdGhlbiBtYWtlIHAgdGhlIHNhbWUgYXMgdGhlIGN1cnJlbnQgcAogICAgICBhY2NlcHRlZF9wW2ldIDwtIFRSVUUKICAgICAgcFtpICsgMV0gPC0gcHByb3BbaV0KICAgIH0KICAgIAogIH0KICAKICAjIGluIHRoZSBlbmQsIG1ha2UgYSB0aWJibGUgYW5kIHJldHVybgogIHRpYmJsZShzd2VlcCA9IDE6KHN3ZWVwcyArIDEpLAogICAgICAgICBmID0gZiwKICAgICAgICAgcCA9IHAsIAogICAgICAgICBwcm9wb3NlZF9mID0gZnByb3AsCiAgICAgICAgIHByb3Bvc2VkX3AgPSBwcHJvcCwKICAgICAgICAgbWhfcmF0aW9fZiA9IG1oX3JhdGlvX2YsCiAgICAgICAgIG1oX3JhdGlvX3AgPSBtaF9yYXRpb19wLAogICAgICAgICBhY2NlcHRlZF9mID0gYWNjZXB0ZWRfZiwKICAgICAgICAgYWNjZXB0ZWRfcCA9IGFjY2VwdGVkX3AKICAgICAgICAgKQp9CmBgYAoKCiMjIFVzaW5nIHRoZSBzYW1wbGVycwoKRWFjaCBvZiB0aGVzZSBNZXRyb3BvbGlzLUhhc3RpbmdzIHNhbXBsZXJzIHJldHVybnMgb3V0cHV0IGluIGEgdGliYmxlLiBGb3IgZXhhbXBsZToKYGBge3J9Cm1jbWNfY3dfbWgobmRhdGEgPSBjKDMwLCAxMCwgMTApKQpgYGAKCiMjIEV4ZXJjaXNlcwoKMS4gUnVuIGVhY2ggb2YgdGhlIHNhbXBsZXJzIGZvciA1MDAwIHN3ZWVwcywgd2l0aCBgbmRhdGEgPSBjKDMwLCAxMCwgMTApYC4KYGBge3J9Cm1jbWNfcnVuIDwtIGxpc3QoCiAgY29tcG9uZW50X3dpc2UgPSBtY21jX2N3X21oKG5kYXRhID0gYygzMCwgMTAsIDEwKSwgc3dlZXBzID0gNTAwMCksCiAgdHdvX2Rfc2FtcGxlciA9IG1jbWNfMmRfbWgobmRhdGEgPSBjKDMwLCAxMCwgMTApLCBzd2VlcHMgPSA1MDAwKQopICU+JQogIGJpbmRfcm93cyguaWQgPSAic2FtcGxlciIpCmBgYAoKMi4gUGxvdCB0aGUgdHJhY2VzIGZvciAkZiQgYW5kICRwJCBmb3IgYm90aCB0aGUgMi1kIGFuZCB0aGUgY29tcG9uZW50d2lzZSBzYW1wbGVyLiBBcmUgdGhleSB2aXNpYmx5IGRpZmZlcmVudD8KYGBge3J9CiMgbG9vayBhdCB0aGUgZidzCmdncGxvdChtY21jX3J1biwgYWVzKHggPSBzd2VlcCwgeSA9IGYpKSArCiAgZ2VvbV9saW5lKCkgKwogIGZhY2V0X3dyYXAofiBzYW1wbGVyLCBucm93ID0gMSkKYGBgCgpgYGB7cn0KIyBsb29rIGF0IHRoZSBwJ3MKZ2dwbG90KG1jbWNfcnVuLCBhZXMoeCA9IHN3ZWVwLCB5ID0gcCkpICsKICBnZW9tX2xpbmUoKSArCiAgZmFjZXRfd3JhcCh+IHNhbXBsZXIsIG5yb3cgPSAxKQpgYGAKCgozLiBDb21wYXJlIHRoZSBhY2NlcHRhbmNlIHJhdGVzIGZvciAkcCQgYW5kICRmJCBmb3IgYm90aCBzYW1wbGVycy4gCmBgYHtyfQptY21jX3J1biAlPiUKICBncm91cF9ieShzYW1wbGVyKSAlPiUKICBzdW1tYXJpc2UoCiAgICBmX2FjY2VwdCA9IG1lYW4oYWNjZXB0ZWRfZiwgbmEucm0gPSBUUlVFKSwKICAgIHBfYWNjZXB0ID0gbWVhbihhY2NlcHRlZF9wLCBuYS5ybSA9IFRSVUUpCiAgKQpgYGAKNC4gSW4gMyB5b3Ugc2hvdWxkIGhhdmUgZm91bmQgdGhhdCB0aGUgYWNjZXB0YW5jZSByYXRlIGlzIGhpZ2hlciBpbiB0aGUgY29tcG9uZW50LXdpc2Ugc2FtcGxlciAoYXMgZXhwZWN0ZWQpLgoKNS4gVGhpcyB3YXMgYSBzaW1wbGUgZXhlcmNpc2UgaW4gc2FtcGxpbmcgY29udGludW91cyByYW5kb20gdmFyaWFibGVzIGFjY29yZGluZyB0byBhIHR3byBkaW1lbnNpb25hbApwb3N0ZXJpb3Igc3VyZmFjZS4gIE5vdywgaW1hZ2luZSB0aGF0IHRoZSBzdGFuZGFyZCBkZXZpYXRpb25zIG9mIHRoZSBwcm9wb3NhbCBkaXN0cmlidXRpb25zIGZvciAkcCQgYW5kICRmJCBhcmUgZml4ZWQsIHRoZW4sIGRyYXcgKGJ5IGhhbmQpIHRoZSBsZXZlbCBjdXJ2ZXMgKGEgImNvbnRvdXIiIHBsb3QpIG9mIGEgMi1kIHBvc3RlcmlvciBzdXJmYWNlIGZvciB3aGljaCB0aGUKMi1kIHNhbXBsZXIgbWlnaHQgaGF2ZSBhIGhpZ2hlciBhY2NlcHRhbmNlIHJhdGUgdGhhbiB0aGUgY29tcG9uZW50IHdpZGUgc2FtcGxlci4gIERyYXcgdGhlIHN0YW5kYXJkIGRldmlhdGlvbnMKb2YgdGhlIHByb3Bvc2FsIGRpc3RyaWJ1dGlvbnMgb24gZm9yIHNjYWxlLgoKX0EgdHdvIGRpbWVuc2lvbmFsIHN1cmZhY2UgdGhhdCBpcyAidGlsdGVkIiAoc2hvd2luZyBoaWdoIGNvcnJlbGF0aW9uIGJldHdlZW4gZiBhbmQgcCkuIElmIHRoZSBzdGFuZGFyZCBkZXZhdGlvbiBpcyBtdWNoIGdyZWF0ZXIgdGhhbiB0aGUgIndpZHRoIiBvZiB0aGUgcG9zdGVyaW9yLCB0aGVuIGNoYW5nZXMgaW4gb25seSBmIG9yIHAgd291bGQgb2Z0ZW4KYmUgcmVqZWN0ZWRfCgpGb3IgZXhhbXBsZToKYGBge3IsIGVjaG89RkFMU0UsIG91dC53aWR0aD0nMTAwJSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJpbWFnZXMvdGlsdGVkLmpwZyIpCmBgYAoKCiMjIFJldmlldyBvZiB0aGUgbW9kZWwgeyNyZXZpZXd9CgpXZSBhcmUgZGVhbGluZyB3aXRoIGEgdmVyeSBzaW1wbGUgbW9kZWwgZm9yIGluYnJlZWRpbmcuICBJdCBpcyBvbmUgdHlwZSBvZgptb2RlbCB0aGF0IG1pZ2h0IGJlIHVzZWQgdG8gYWNjb3VudCBmb3IgYW4gZXhjZXNzIG9mIGhvbW96eWdvdGVzIGluIGEgc2FtcGxlIApmcm9tIGEgcG9wdWxhdGlvbi4gIFdlIGFzc3VtZSB0aGF0IHdlIGhhdmUgdGFrZW4gYSBzYW1wbGUgb2YgJG4kIGRpcGxvaWQKaW5kaXZpZHVhbHMgZnJvbSB0aGUgcG9wdWxhdGlvbiwgYW5kIHdlIHdpbGwgYmUgY29uc2lkZXJpbmcganVzdCBhIHNpbmdsZQpsb2N1cyBhdCBhIHRpbWUuICAgVGhpcyBsb2N1cyBoYXMgdHdvIGFsbGVsZXMgJEEkIGFuZCAkYSQsIGFuZCBvdXIgc2FtcGxlIApjYW4gYmUgc3VtbWFyaXplZCBieSAod2hhdCB0dXJucyBvdXQgdG8gYmUgdGhlIHN1ZmZpY2llbnQgc3RhdGlzdGljLCBpbiB0aGlzCmNhc2UpIHRoZSBudW1iZXJzIG9mIHRoZSB0aHJlZSBwb3NzaWJsZSBnZW5vdHlwZXM6ICRuX3tBQX0kLCB0aGUgbnVtYmVyIG9mCiRBQSQgaG9tb3p5Z290ZXM7ICRuX3tBYX0kLCB0aGUgbnVtYmVyIG9mIGhldGVyb3p5Z290ZXM7IGFuZCAkbl97YWF9JCwgdGhlCm51bWJlciBvZiAkYWEkIGhvbW96eWdvdGVzLiAgT2YgY291cnNlLCAkbl97QUF9ICsgbl97QWF9ICsgbl97YWF9ID0gbiQuCgpJbiBhIHBvcHVsYXRpb24gd2l0aCBubyBpbmJyZWVkaW5nLCB0aGUgZXhwZWN0ZWQgZnJhY3Rpb24gb2YgZ2Vub3R5cGVzIGZvbGxvd3MKdGhlIEhhcmR5LVdlaW5iZXJnIGVxdWlsaWJyaXVtIHByb3BvcnRpb25zLiAgTGV0dGluZyAkcCQgZGVub3RlIHRoZSBmcmVxdWVuY3kgb2YgdGhlCiRBJCBhbGxlbGUgaW4gdGhlIHBvcHVsYXRpb24sIHVuZGVyIEhhcmR5LVdlaW5iZXJnIGVxdWlsaWJyaXVtIHRoZSwgZXhwZWN0ZWQgZnJhY3Rpb25zCm9mIHRoZSBkaWZmZXJlbnQgZ2Vub3R5cGVzIGFyZToKJCQKXGJlZ2lue2FsaWduZWR9ClBfXG1hdGhybXtIV30oQUEpICYgPSBwXjIgXFwKUF9cbWF0aHJte0hXfShBYSkgJiA9IDJwKDEtcClcXApQX1xtYXRocm17SFd9KGFhKSAmID0gKDEtcCleMgpcZW5ke2FsaWduZWR9CiQkCgojIyMgQmFzaWMgcHJvYmFiaWxpdGllcwoKSW5icmVlZGluZyBpbiBhIHBvcHVsYXRpb24gdmlvbGF0ZXMgb25lIG9mIHRoZSBtYW55IGFzc3VtcHRpb25zIHJlcXVpcmVkIGZvciBIYXJkeS1XZWluYmVyZwplcXVpbGlicml1bSB0byBob2xkLiAgV2UgbW9kZWwgaW5icmVlZGluZyBoZXJlIGFzIGEgcHJvcGVydHkgb2YgdGhlIHBhaXIgb2YgZ2VuZSBjb3BpZXMKdGhhdCBvY2N1ciBpbiBhbiBpbmRpdmlkdWFsIGluIHRoZSBwb3B1bGF0aW9uLCBhbmQgd2UgbWVhc3VyZSBpdCB3aXRoIHRoZSBwb3B1bGF0aW9uCmluYnJlZWRpbmcgY29lZmZpY2llbnQsICRmJCwgd2hpY2ggY2FuIGJlIGludGVycHJldGVkIGFzIHRoZSBwcm9iYWJpbGl0eQp0aGF0IHRoZSBwYWlyIG9mIGdlbmUgY29waWVzIGluIGFuIGluZGl2aWR1YWwgcmFuZG9tbHkgc2FtcGxlZCBmcm9tIHRoZSBwb3B1bGF0aW9uIGFyZSBfaWRlbnRpY2FsCmJ5IGRlc2NlbnRfLCBvciBJQkQgZm9yIHNob3J0LiAgRm9yIG91ciBwdXJwb3NlcyBpbiB0aGlzIHNlc3Npb24sIHdlIHdpbGwgdGFrZSAiaWRlbnRpY2FsIGJ5IGRlc2NlbnQiIHRvIG1lYW4gdGhhdAp0aGV5IGFyZSBib3RoIGNvcGllcyBvZiB0aGUgc2FtZSwgcmVjZW50IGFuY2VzdHJhbCBnZW5lIGNvcHkuICBNb3JlIGltcG9ydGFudCB0aGFuIHRoZSBleGFjdApkZWZpbml0aW9uIG9mICJpZGVudGljYWwgYnkgZGVzY2VudCIgYWRvcHRlZCBoZXJlIGFyZSB0aGUgY29uc2VxdWVuY2VzIGZvciB0d28gZ2VuZSBjb3BpZXMgb2YKYmVpbmcgSUJELiAgQW5kIGluIHRoaXMgY2FzZSwgdGhhdCBpcyB2ZXJ5IHNpbXBsZTogd2Ugd2lsbCBhc3N1bWUgdGhhdCBpZiAKdHdvIGdlbmUgY29waWVzIGFyZSBJQkQsIHRoZW4gdGhleSBtdXN0IGFsc28gYmUgdGhlIHNhbWUgYWxsZWxpYyB0eXBlLiAgSW4gb3RoZXIKd29yZHMsIGlmIHR3byBnZW5lIGNvcGllcyBhcmUgSUJELCBhbmQgdGhlIGZpcnN0IG9mIHRoZW0gaXMgYWxsZWxlICRBJCwgdGhlbiB0aGUgc2Vjb25kIG11c3QKYWxzbyBiZSBhbGxlbGUgJEEkLiAgCgpTbywgZ2l2ZW4gdGhlIGluYnJlZWRpbmcgY29lZmZpY2llbnQgJGYkLCB3ZSBjYW4gY29tcHV0ZSB0aGUgcHJvYmFiaWxpdHkgdGhhdAphIHJhbmRvbWx5IHNhbXBsZWQgaW5kaXZpZHVhbCBoYXMgdGhlIGdlbm90eXBlICRBQSQsICRBYSQsIG9yICRhYSQuICBGaXJzdCwgbGV0IHVzIGNvbnNpZGVyCiRQKEFBKSQ6IHdpdGggcHJvYmFiaWxpdHkgJGYkIHRoZSB0d28gZ2VuZSBjb3BpZXMgYXQgYSBsb2N1cyBpbiB0aGUgaW5kaXZpZHVhbCBhcmUgSUJELCAKaW4gd2hpY2ggY2FzZSBvbmx5IHRoZSBmaXJzdCBnZW5lIGNvcHkgbXVzdCBieSAkQSQsIHNpbmNlIHRoZSBzZWNvbmQgb25lIHdpbGwgYmUgdG9vLiAgT24gdGhlIG90aGVyIGhhbmQsIHdpdGggcHJvYmFiaWxpdHkgJCgxLWYpJCB0aGUgdHdvIGdlbmUgY29waWVzIGF0IHRoZSBsb2N1cyBpbiB0aGUKaW5kaXZpZHVhbCBhcmUgbm90IElCRCwgYW5kIHNvIHRoZSBwcm9iYWJpbGl0eSBvZiBiZWluZyAkQUEkIGlzIGp1c3QgdGhlIHN0YW5kYXJkIEhhcmR5LVdlaW5iZXJnIApwcm9iYWJpbGl0eSwgJFBfXG1hdGhybXtIV30oQUEpID0gcF4yJC4gIEhlbmNlLCB1bmRlciB0aGUgaW5icmVlZGluZyBtb2RlbDoKJCQKXGJlZ2lue2FsaWduZWR9ClAoQUEpICY9IGZwICsgKDEtZilwXjIgXFwKUChBYSkgJj0gZlx0aW1lcyAwICsgKDEtZikycCgxLXApIFxcClAoYWEpICY9IGYoMS1wKSArICgxLWYpKDEtcCleMgpcZW5ke2FsaWduZWR9CiQkCgojIyMgVGhlIGxpa2VsaWhvb2QKTm93IHJlY2FsbCB0aGF0IG91ciBkYXRhIGFyZSAkKG5fe0FBfSwgbl97QWF9LCBuX3thYX0pJC0tLXRoZSBudW1iZXJzIG9mIHRoZSBkaWZmZXJlbnQgZ2Vub3R5cGVzCm9ic2VydmVkIGluIHRoZSBzYW1wbGUuICBUbyBtb3ZlIGZvcndhcmQgaW4gaW5mZXJlbmNlLCB3ZSBuZWVkIHRvIGJlIGFibGUgdG8gY29tcHV0ZSB0aGUgCmxpa2VsaWhvb2QsIHdoaWNoIGlzIHRoZSBwcm9iYWJpbGl0eSBvZiBvdXIgZGF0YSBnaXZlbiB0aGUgdmFsdWVzIG9mIHRoZSBwYXJhbWV0ZXJzOiAkUChuX3tBQX0sIG5fe0FhfSwgbl97YWF9fHAsZikkLgpOb3RlIGhlcmUgdGhhdCB0aGUgdHdvIHBhcmFtZXRlcnMgaW4gb3VyIG1vZGVsIGFyZSAkcCQsIHRoZSBmcmVxdWVuY3kgb2YgdGhlICRBJCBhbGxlbGUgaW4gdGhlIHBvcHVsYXRpb24sCmFuZCAkZiQsIHRoZSBwb3B1bGF0aW9uIGluYnJlZWRpbmcgY29lZmZpY2llbnQuICBXZSBhc3N1bWUgdGhhdCBlYWNoIGluZGl2aWR1YWwgaXMgc2FtcGxlZCBpbmRlcGVuZGVudGx5CmZyb20gdGhlIHBvcHVsYXRpb24sIHNvIHRoZSBsaWtlbGlob29kIGlzIGEgbXVsdGlub21pYWw6CiQkClAobl97QUF9LCBuX3tBYX0sIG5fe2FhfSkgPSBcZnJhY3tuIX17bl97QUF9ISArIG5fe0FhfSEgKyBuX3thYX0hfX4KW2ZwICsgKDEtZilwXjJdXntuX3tBQX19fgpbKDEtZikycCgxLXApXV57bl97QWF9fX4KW2YoMS1wKSArICgxLWYpKDEtcCleMl1ee25fe2FhfX0KJCQKVGhlIG11bHRpbm9taWFsIGNvZWZmaWNpZW50IGlzIGEgY29uc3RhbnQgd2l0aCByZXNwZWN0IHRvICRwJCBhbmQgJGYkIHNvIGl0IHdpbGwgZHJvcCBvdXQuICAKCiMjIyBUaGUgcHJpb3JzCgpXZSBuZWVkIHByaW9ycyBvZiAkcCQgYW5kICRmJC4gIFRoZXNlIGFyZSBwcm9wb3J0aW9ucywgc28gYSBuYXR1cmFsIGNob2ljZSBpcyB0aGUgYmV0YSBkaXN0cmlidXRpb24uICAKTGV0J3MgZGVmaW5lICRmIFxzaW0gXG1hdGhybXtCZXRhfShcYWxwaGFfZiwgXGJldGFfZikkIGFuZCAkcCBcc2ltIFxtYXRocm17QmV0YX0oXGFscGhhX3AsIFxiZXRhX3ApJCwKYW5kIHdlIHdpbGwgc2V0IHVwIG91ciBtb2RlbCB0aGF0IHdheSwgdGhvdWdoIHRoZSBkZWZhdWx0IHZhbHVlcyB3ZSB3aWxsIHVzZSBhcmUKJFxhbHBoYV9mID0gXGJldGFfZiA9IFxhbHBoYV9wID0gXGJldGFfcCA9IDEkIHdoaWNoIHdpbGwgZ2l2ZSB1cyB1bmlmb3JtIHByaW9ycyBmb3IgJGYkIGFuZCAkcCQuICAK